﻿#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <unistd.h>
//#include <sys/types.h>
//#include <errno.h>
#include <functional>

#include "SL_net_inner.h"
#include "SLT_log.h"
#include "SL_tcpClient.h"
#include "SL_tcpClient_event_impl.h"
#include "SL_tcpServer_event_impl.h"

#define _TCPSERVER_LOG_DEBUG(_format,...)   SLT_LOG(1,SLT_DEBUG,"[tcp]" _format, ##__VA_ARGS__)
#define _TCPSERVER_LOG_INFO(_format,...) SLT_LOG(1,SLT_INFO,"[tcp]" _format, ##__VA_ARGS__)
#define _TCPSERVER_LOG_ERR(_format,...) SLT_LOG(1,SLT_ERROR,"[tcp]" _format, ##__VA_ARGS__)

void SLT_libeventInit();
SLTcpServerEventImpl::SLTcpServerEventImpl()
{
}
SLTcpServerEventImpl::~SLTcpServerEventImpl()
{
	if (m_base) {
		event_base_loopbreak(m_base);
	}
	if (m_pthread) {
		m_pthread->join();
		delete m_pthread;
		m_pthread = nullptr;
	}

	m_connect_info.clear();
	m_clientMap.clear();
	
	if (m_base) {
		event_base_free(m_base);
	}
}
int SLTcpServerEventImpl::init(SLTcpServerCB* pcb)
{
	SLT_libeventInit();
	if (nullptr != m_base) {
		return -2;
	}

	m_pcb = pcb;
	m_base = event_base_new();
	if (!m_base) {
		_TCPSERVER_LOG_ERR("Could not initialize libevent!");
		return -1;
	}

	/* Create a pair of sockets */
	if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, m_event_pair) == -1) {
		_TCPSERVER_LOG_ERR("evutil_socketpair error");
		return -2;
	}
	struct event* ev = event_new(m_base, m_event_pair[1], EV_CLOSED | EV_READ | EV_PERSIST, eventNotify_cb_g, this);
	event_add(ev, 0);

	//添加定时器
	static timeval t2;
	t2.tv_sec = 1;
	t2.tv_usec = 0;
	event* timer2 = event_new(m_base, -1, EV_PERSIST, checkTimeOut_g, this);
	event_add(timer2, &t2);
	return 0;
}
void SLTcpServerEventImpl::start()
{
	m_pthread = new std::thread(std::bind(&SLTcpServerEventImpl::thread_listen, this));
}
void SLTcpServerEventImpl::thread_listen()
{
	event_base_loop(m_base, EVLOOP_NO_EXIT_ON_EMPTY);
}
int SLTcpServerEventImpl::addListen(std::string _ip, int& _port)
{
	if (_ip.empty()) {
		_ip = "0.0.0.0";
	}
	_TCPSERVER_LOG_INFO("add listen:%s,%d", _ip.c_str(), _port);

	SLTcpClientEventImpl::_tcp_event_infoStpr  pevinfo(new SLTcpClientEventImpl::_tcp_event_info);
	pevinfo->m_cmd = EPOLL_LIST_CMD_ADD_LISTEN_SOCKET;
	pevinfo->m_listenip = _ip;
	pevinfo->m_listenport = _port;
	pushEvent(pevinfo);  //切换线程调用createFd

	//异步转同步，等待监听完毕
	while (!pevinfo->m_runState) {
		//printf("loading....  \n\n");
		SLT_sleep(5);
	}
	if (0 != pevinfo->m_result) {
		_TCPSERVER_LOG_ERR("add listen error:%s,%d,ret:%d", _ip.c_str(), _port, pevinfo->m_result);
	}
	else {
		_port = pevinfo->m_listenport;
		_TCPSERVER_LOG_INFO("add listen success:%s,%d", _ip.c_str(), _port);
	}
	return pevinfo->m_result;
}
int SLTcpServerEventImpl::delListen(std::string _ip, int _port)
{
	if (_ip.empty()) {
		_ip = "0.0.0.0";
	}
    _TCPSERVER_LOG_INFO("del listen:%s,%d", _ip.c_str(), _port);

    SLTcpClientEventImpl::_tcp_event_infoStpr  pevinfo(new SLTcpClientEventImpl::_tcp_event_info);
    pevinfo->m_cmd = EPOLL_LIST_CMD_DEL_LISTEN_SOCKET;
    pevinfo->m_listenip = _ip;
    pevinfo->m_listenport = _port;
    pushEvent(pevinfo);  //切换线程调用createFd

    //异步转同步，等待监听完毕
    while (!pevinfo->m_runState) {
        SLT_sleep(5);
    }
    if (0 != pevinfo->m_result) {
        _TCPSERVER_LOG_ERR("del listen error : %s, %d ,ret : %d", _ip.c_str(), _port, pevinfo->m_result);
    }
    else {
        _TCPSERVER_LOG_INFO("del listen success : %s, %d", _ip.c_str(), _port);
    }
    return pevinfo->m_result;
}

void SLTcpServerEventImpl::listener_cb(struct evconnlistener* listener, evutil_socket_t fd,	struct sockaddr* sa, int socklen, void* user_data) 
{
	((_tcp_listen_info*)user_data)->pserver->listener_cb_fun(listener, fd, sa, socklen, (_tcp_listen_info*)user_data);
}
void SLTcpServerEventImpl::listener_cb_fun(struct evconnlistener* listener, evutil_socket_t fd,	struct sockaddr* sa, int socklen, _tcp_listen_info* _plistenInfo)
{
	SLTcpClientEventImplPtr pnewClient = std::make_shared<SLTcpClientEventImpl>(m_clientIDBase++);
	if (pnewClient) {
		if(0 != pnewClient->initSocket(m_base,fd)){
			_TCPSERVER_LOG_ERR("initSocket error!");
			return;
		}
		struct sockaddr_in* pradd = (struct sockaddr_in*)sa;
		pnewClient->m_lip = _plistenInfo->m_ip;
		pnewClient->m_lport = _plistenInfo->m_port;
		pnewClient->m_socket = fd;
		pnewClient->m_rip = ntohl(pradd->sin_addr.s_addr);
		pnewClient->m_rport = ntohs(pradd->sin_port);;
		pnewClient->m_pserver = this;

		_TCPSERVER_LOG_INFO("accept,%s", pnewClient->toString().c_str());
		pnewClient->m_workState = SLTcpClientEventImpl::tcp_work_state_ok;
		m_clientMap.insert(make_pair(pnewClient->m_clientID, pnewClient));
		SLTcpClientPtr tptr = std::static_pointer_cast<SLTcpClient>(pnewClient);
		m_pcb->TcpServer_onConnect(tptr);
	}
	else {
		_TCPSERVER_LOG_ERR("new connect,memory error!!.lport:%d", _plistenInfo->m_port);
	}
}
SLTcpClientPtr  SLTcpServerEventImpl::createClient()
{
	SLTcpClientEventImplPtr pc = std::make_shared<SLTcpClientEventImpl>((uint32_t)m_clientIDBase++);
	pc->m_pserver = this;
	return std::static_pointer_cast<SLTcpClient>(pc);
}
void SLTcpServerEventImpl::pushEvent(SLTcpClientEventImpl::_tcp_event_infoStpr pevInfo)
{
	//保存后由队列负责释放
	m_eventListLock.lock();
	m_eventList.push_back(pevInfo);
	if (! m_beventRun) {
		if (send(m_event_pair[0], "a", 1, 0) < 0) {
			_TCPSERVER_LOG_ERR("tcp server event send error !!!");
		}
		else {
			m_beventRun = true;
		}
	}
	m_eventListLock.unlock();
}
void SLTcpServerEventImpl::eventNotify_cb(evutil_socket_t fd, short event)
{
	if (EV_CLOSED & event) {
		_TCPSERVER_LOG_ERR("tcp server event fd close. error !!!");
		return;
	}

	if (EV_READ & event) {
		char buf[8] = { 0 };
		int recvlen = recv(fd, buf, sizeof(buf), 0);
		if (recvlen <= 0) {
			_TCPSERVER_LOG_ERR("tcp server event fd read error : %d", recvlen);
		}
		else {
			std::deque< SLTcpClientEventImpl::_tcp_event_infoStpr> tempList;
			while (1) {
				tempList.clear();
				m_eventListLock.lock();
				if (m_eventList.empty()) {
					m_beventRun = false;
					m_eventListLock.unlock();
					break;
				}

				for (int j = 0; j < 10 && !m_eventList.empty(); j++) {
					tempList.push_back(m_eventList.front());
					m_eventList.pop_front();
				}
				m_eventListLock.unlock();

				while (!tempList.empty()) {
					SLTcpClientEventImpl::_tcp_event_info* pevinfo = tempList.front().get();
					eventNotify_cb_fun(pevinfo);
					tempList.pop_front();
				}
			}
		}
	}
}
void SLTcpServerEventImpl::eventNotify_cb_fun(SLTcpClientEventImpl::_tcp_event_info* _evinfo)
{
    if (EPOLL_LIST_CMD_ADD_LISTEN_SOCKET == _evinfo->m_cmd) {
        struct sockaddr_in sin = { 0 };
        sin.sin_family = AF_INET;
        sin.sin_port = htons(_evinfo->m_listenport);
        if (!_evinfo->m_listenip.empty()) {
            sin.sin_addr.s_addr = htonl(SLT_ip2num(_evinfo->m_listenip.c_str()));
        }
        /*else {
            sin.sin_addr.s_addr = INADDR_ANY;
        }*/

		
		std::string key = _evinfo->m_listenip + "_" + std::to_string(_evinfo->m_listenport);
		if (m_connect_info.end() != m_connect_info.find(key))
		{
			//检查重复
			_evinfo->m_result = -2;
		}else{
			_tcp_listen_info* plinfo = new _tcp_listen_info;
			plinfo->m_ip = SLT_ip2num(_evinfo->m_listenip.c_str());
			plinfo->m_port = _evinfo->m_listenport;
			plinfo->pserver = this;
			//std::shared_ptr<_tcp_listen_info> listenSptr1 = std::make_shared<_tcp_listen_info>([](_tcp_listen_info *p){if(p) delete(p);});
			//std::shared_ptr<_tcp_listen_info> listenSptr2 = std::make_shared<_tcp_listen_info>();
			//std::shared_ptr<_tcp_listen_info> listenSptr3 = std::shared_ptr<_tcp_listen_info>(plinfo, [](_tcp_listen_info* p) {if (p) delete(p); });
			std::shared_ptr<_tcp_listen_info> listenSptr(plinfo);

			struct evconnlistener* listener = evconnlistener_new_bind(m_base, listener_cb, (void*)plinfo, LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, -1,
				(struct sockaddr*)&sin, sizeof(sin));
			if (!listener) {
				_evinfo->m_result = -1;
			}
			else {
				listenSptr->listener = listener;
				evutil_socket_t fd = evconnlistener_get_fd(listener);
				uint16_t sPort = 0;
				if (listenSptr->m_port == 0) {
					if (0 != SLT_getSocketInfoV4_inner(fd, sPort)) {
						_evinfo->m_result = -3;
					}
					else {
						_evinfo->m_listenport = sPort;
						listenSptr->m_port = sPort;
					}
				}
				if(listenSptr->m_port != 0){
					std::string key = _evinfo->m_listenip + "_" + std::to_string(listenSptr->m_port);
					m_connect_info.insert({ key, listenSptr });
					_evinfo->m_result = 0;
				}				
			}	
		}
		_evinfo->m_runState = true; //执行结束
    }
    else if (EPOLL_LIST_CMD_DEL_LISTEN_SOCKET == _evinfo->m_cmd)
    {
		std::string key = _evinfo->m_listenip + "_" + std::to_string(_evinfo->m_listenport);
        auto iter = m_connect_info.find(key);
        if (iter != m_connect_info.end())
        {
            m_connect_info.erase(iter);
            _TCPSERVER_LOG_ERR("tcp server del listen ip : %s, port : %d", _evinfo->m_listenip.c_str(), _evinfo->m_listenport);
        }
        _evinfo->m_result = 0;
        _evinfo->m_runState = true; //执行结束

	}else if (EPOLL_LIST_CLIENT_CONNECT == _evinfo->m_cmd) {
		SLTcpClientEventImpl* pclient = _evinfo->m_client.get();
		if(_evinfo->m_connectState == 0){
			//保存
			m_clientMap.insert(make_pair(pclient->m_clientID, _evinfo->m_client));
			pclient->initSocket(m_base,_evinfo->m_socket);
		}
	}else if (EPOLL_LIST_SOCKET_DEL == _evinfo->m_cmd) {
		SLTcpClientEventImpl* pclient = _evinfo->m_client.get();
		auto clientIter = m_clientMap.find(pclient->m_clientID);
		if (clientIter != m_clientMap.end()) {
			//关闭客户端
			pclient->onError(tcp_error_type_localclose);
			m_clientMap.erase(clientIter);
			NetClose(_evinfo->m_socket);
		}
	}else if( _evinfo->m_cmd == EPOLL_LIST_SOCKET_STARTRECV || _evinfo->m_cmd == EPOLL_LIST_SOCKET_RECVDATAONE){
		SLTcpClientEventImpl* pclient = _evinfo->m_client.get();
		auto iter = m_clientMap.find(pclient->m_clientID);
		if (iter != m_clientMap.end())
		{
			iter->second->onRecvFromNet();
			//recvData(iter->second);
		}
	}
}
void SLTcpServerEventImpl::checkTimeOut_g(evutil_socket_t fd, short event, void* arg)
{
	((SLTcpServerEventImpl*)arg)->checkTimeOut();
}
void SLTcpServerEventImpl::checkTimeOut()
{
	for (auto& cli : m_clientMap) {
		if (cli.second->m_isActive) {
			cli.second->m_isActive = false;
			cli.second->m_lastActiveTime.start();
		}
		else {
			//超过3分钟
			if (cli.second->m_lastActiveTime.elapseMs() > 180000) {
				cli.second->onError(tcp_error_type_timeout);
			}
		}
	}
}
void SLTcpServerEventImpl::NetClose(int socket)
{
	if (socket == -1) {
		return;
	}
#ifdef WIN32
    closesocket(socket);
#else
    close(socket);
#endif
}
